#ifndef ejemplo1_phs
#define ejemplo1_phs
#include "prelude.h"

/*
pHaskell Code: 


--Suma dos numeros
sum::int->int->int
sum x y = x+y 

--Funcion principal
mainfunction::int
mainfunction = sum 1 2
*/


/*
Lambda Abstraction: 

length = (\metaemptylist<>:(metalist) -> 0)
[]
length = (\metalist<Variable(x)Variable(xs)>:(metalist) -> Variable(pAdd) (1) (Variable(length) (Variable(xs))))
[]
head = (\metalist<Variable(x)Variable(xs)>:(metalist) -> Variable(x))
[]
tail = (\metalist<Variable(x)Variable(xs)>:(metalist) -> Variable(xs))
[]
take = (\0:(int->metalist) -> (\Variable(x):(metalist) -> metaemptylist<>))
[]
take = (\Variable(n):(int->metalist) -> (\metaemptylist<>:(metalist) -> metaemptylist<>))
[]
take = (\Variable(n):(int->metalist) -> (\metalist<Variable(x)Variable(xs)>:(metalist) -> metalist<Variable(x)Variable(take) (Variable(pMinus) (Variable(n)) (1)) (Variable(xs))>))
[]
max = (\Variable(x):(int->int) -> (\Variable(y):(int) -> (if Variable(pGreat) (Variable(x)) (Variable(y)) then Variable(x) else (Variable(y) endif)))
[]
min = (\Variable(x):(int->int) -> (\Variable(y):(int) -> (if Variable(pGreat) (Variable(y)) (Variable(x)) then Variable(x) else (Variable(y) endif)))
[]
abs = (\Variable(x):(int) -> (if Variable(pGreat) (Variable(x)) (0) then Variable(x) else ((if Variable(pLess) (Variable(x)) (0) then Variable(pNeg) (Variable(x)) endif) endif))
[]
sum = (\Variable(x):(int->int) -> (\Variable(y):(int) -> Variable(pAdd) (Variable(x)) (Variable(y))))
[]
mainfunction = Variable(sum) (1) (2)
[]

*/


/* META-TYPE SECTION */

/* Type: metalist */
template< class x0, class x1 >
struct metalist{
typedef metalist<x0, x1>  value;
};

template< class = void >
struct metaemptylist{
typedef metaemptylist value;
};



/* MAIN SECTION */


struct length
{
    struct _
    {
    typedef _ value;
    template< class ,class=void>
    struct app_matching;

    template<class BridgeEager45344>
    struct app:app_matching< typename BridgeEager45344::value > {}; //eager bridge 

      template< class dummy_PMetaLambda_PMetaPrograms_>
      struct app_matching< metaemptylist< >, dummy_PMetaLambda_PMetaPrograms_ >
      {
          struct _:  Int<0> 
          {
          typedef Int<0> ::value value;
          };
      };
      template< class x, class xs, class dummy_PMetaLambda_PMetaPrograms_>
      struct app_matching< metalist<x, xs >, dummy_PMetaLambda_PMetaPrograms_ >
      {
          struct _:  pAdd::_::template app<Int<1>  >::_::template app<typename length::_::template app<xs >::_ >::_
          {
          typedef typename pAdd::_::template app<Int<1>  >::_::template app<typename length::_::template app<xs >::_ >::_::value value;
          };
      };
    };
};

struct head
{
    struct _
    {
    typedef _ value;
    template< class ,class=void>
    struct app_matching;

    template<class BridgeEager45344>
    struct app:app_matching< typename BridgeEager45344::value > {}; //eager bridge 

      template< class x, class xs, class dummy_PMetaLambda_PMetaPrograms_>
      struct app_matching< metalist<x, xs >, dummy_PMetaLambda_PMetaPrograms_ >
      {
          struct _:  x
          {
          typedef typename x::value value;
          };
      };
    };
};

struct tail
{
    struct _
    {
    typedef _ value;
    template< class ,class=void>
    struct app_matching;

    template<class BridgeEager45344>
    struct app:app_matching< typename BridgeEager45344::value > {}; //eager bridge 

      template< class x, class xs, class dummy_PMetaLambda_PMetaPrograms_>
      struct app_matching< metalist<x, xs >, dummy_PMetaLambda_PMetaPrograms_ >
      {
          struct _:  xs
          {
          typedef typename xs::value value;
          };
      };
    };
};

struct take
{
    struct _
    {
    typedef _ value;
    template< class ,class=void>
    struct app_matching;

    template<class BridgeEager45344>
    struct app:app_matching< typename BridgeEager45344::value > {}; //eager bridge 

      template< class dummy_PMetaLambda_PMetaPrograms_>
      struct app_matching< Int<0>, dummy_PMetaLambda_PMetaPrograms_>
      {
        struct _
        {
        typedef _ value;
          template< class x, class=void>
          struct app
          {
              struct _:  metaemptylist< >
              {
              typedef typename metaemptylist< >::value value;
              };
          };
        };
      };
      template< class n, class>
      struct app_matching
      {
        struct _
        {
        typedef _ value;
        template< class ,class=void>
        struct app_matching;

        template<class BridgeEager45344>
        struct app:app_matching< typename BridgeEager45344::value > {}; //eager bridge 

          template< class dummy_PMetaLambda_PMetaLambda_PMetaPrograms_>
          struct app_matching< metaemptylist< >, dummy_PMetaLambda_PMetaLambda_PMetaPrograms_ >
          {
              struct _:  metaemptylist< >
              {
              typedef typename metaemptylist< >::value value;
              };
          };
          template< class x, class xs, class dummy_PMetaLambda_PMetaLambda_PMetaPrograms_>
          struct app_matching< metalist<x, xs >, dummy_PMetaLambda_PMetaLambda_PMetaPrograms_ >
          {
              struct _:  metalist<x, typename take::_::template app<typename pMinus::_::template app<n >::_::template app<Int<1>  >::_ >::_::template app<xs >::_ >
              {
              typedef typename metalist<x, typename take::_::template app<typename pMinus::_::template app<n >::_::template app<Int<1>  >::_ >::_::template app<xs >::_ >::value value;
              };
          };
        };
      };
    };
};

struct max
{
    struct _
    {
    typedef _ value;
      template< class x, class=void>
      struct app
      {
        struct _
        {
        typedef _ value;
          template< class y, class=void>
          struct app
          {
              struct _:  IF<typename pGreat::_::template app<x >::_::template app<y >::_, 
                        x, 
                        y >::_
              {
              typedef typename IF<typename pGreat::_::template app<x >::_::template app<y >::_, 
                        x, 
                        y >::_::value value;
              };
          };
        };
      };
    };
};

struct min
{
    struct _
    {
    typedef _ value;
      template< class x, class=void>
      struct app
      {
        struct _
        {
        typedef _ value;
          template< class y, class=void>
          struct app
          {
              struct _:  IF<typename pGreat::_::template app<y >::_::template app<x >::_, 
                        x, 
                        y >::_
              {
              typedef typename IF<typename pGreat::_::template app<y >::_::template app<x >::_, 
                        x, 
                        y >::_::value value;
              };
          };
        };
      };
    };
};

struct abs
{
    struct _
    {
    typedef _ value;
      template< class x, class=void>
      struct app
      {
          struct _:  IF<typename pGreat::_::template app<x >::_::template app<Int<0>  >::_, 
                    x, 
                    typename IF<typename pLess::_::template app<x >::_::template app<Int<0>  >::_, 
                                        typename pNeg::_::template app<x >::_ >::_ >::_
          {
          typedef typename IF<typename pGreat::_::template app<x >::_::template app<Int<0>  >::_, 
                    x, 
                    typename IF<typename pLess::_::template app<x >::_::template app<Int<0>  >::_, 
                                        typename pNeg::_::template app<x >::_ >::_ >::_::value value;
          };
      };
    };
};

struct sum
{
    struct _
    {
    typedef _ value;
      template< class x, class=void>
      struct app
      {
        struct _
        {
        typedef _ value;
          template< class y, class=void>
          struct app
          {
              struct _:  pAdd::_::template app<x >::_::template app<y >::_
              {
              typedef typename pAdd::_::template app<x >::_::template app<y >::_::value value;
              };
          };
        };
      };
    };
};

struct mainfunction
{
      struct _:  sum::_::app<Int<1>  >::_::app<Int<2>  >::_
      {
      typedef sum::_::app<Int<1>  >::_::app<Int<2>  >::_::value value;
      };
};

/* GENERATRIX SECTION */

#endif
